home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume24 / hp next >
Encoding:
Internet Message Format  |  1991-03-13  |  11.5 KB

  1. Subject:  v24i045:  Reverse polish notation calculator
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: 4c44080e 76e021ce 14016090 f4a6a0ff
  5.  
  6. Submitted-by: Arnold Robbins <arnold@audiofax.com>
  7. Posting-number: Volume 24, Issue 45
  8. Archive-name: hp
  9.  
  10. #! /bin/sh
  11. # This is a shell archive, meaning:
  12. # 1. Remove everything above the #! /bin/sh line.
  13. # 2. Save the resulting text in a file.
  14. # 3. Execute the file with /bin/sh (not csh) to create:
  15. #    README
  16. #    hp.1
  17. #    Makefile
  18. #    hp.gram.y
  19. #    hp.scan.l
  20. #    hp.h
  21. #    hp.c
  22. # This archive created: Wed Jan 23 17:27:04 1991
  23. export PATH; PATH=/bin:/usr/bin:$PATH
  24. echo shar: "extracting 'README'" '(499 characters)'
  25. if test -f 'README'
  26. then
  27.     echo shar: "will not over-write existing file 'README'"
  28. else
  29. cat << \SHAR_EOF > 'README'
  30. Wed Jan 23 17:23:32 EST 1991
  31.  
  32. The 'hp' program implements a reverse polish notation calculator.
  33. I've had this little program for over five years, and finally decided
  34. to clean it up a little bit and post it.
  35.  
  36. Enjoy,
  37.  
  38. Arnold Robbins                AudioFAX, Inc. | Laundry increases
  39. 2000 Powers Ferry Road, #200 / Marietta, GA. 30067     | exponentially in the
  40. INTERNET: arnold@audiofax.com Phone:   +1 404 933 7612 | number of children.
  41. UUCP:      emory!audfax!arnold Fax-box: +1 404 618 4581 |   -- Miriam Robbins
  42. SHAR_EOF
  43. fi
  44. echo shar: "extracting 'hp.1'" '(3480 characters)'
  45. if test -f 'hp.1'
  46. then
  47.     echo shar: "will not over-write existing file 'hp.1'"
  48. else
  49. cat << \SHAR_EOF > 'hp.1'
  50. .if n .ds lq ""
  51. .if n .ds rq ""
  52. .if t .ds lq ``
  53. .if t .ds rq ''
  54. .de QU
  55. \&\\*(lq\\$1\\*(rq\\$2
  56. ..
  57. .TH HP 1
  58. .SH NAME
  59. hp \- Reverse Polish Notation calculator
  60. .SH SYNOPSIS
  61. .B hp
  62. [
  63. .I "expression elements"
  64. ]
  65. .SH DESCRIPTION
  66. .I Hp
  67. is a desk calculator program using the Reverse Polish Notation
  68. familiar to all stack machine aficionados and users of
  69. Hewlett-Packard calculators.
  70. It accepts expressions composed of operands and operators from
  71. either its argument list or standard input and evaluates them.
  72. .PP
  73. If the expressions to be evaluated are given on the command line,
  74. .I hp
  75. prints the resulting value automatically;
  76. otherwise, the user must request printing with the
  77. .QU "p"
  78. or
  79. .QU "P"
  80. commands.
  81. .PP
  82. An acceptable expression consists of a sequence of
  83. .QU "constants"
  84. and
  85. .QU "commands."
  86. Constants are numeric constants written in the style of FORTRAN,
  87. and are stored internally as double precision floating-point values.
  88. Commands are single characters that request an arithmetic, stack
  89. control, or control flow operation.
  90. The following commands are currently implemented:
  91. .TP
  92. .B p
  93. print the value on the top of the stack.
  94. .TP
  95. .B P
  96. print all the values currently on the stack.
  97. .TP
  98. .B d
  99. delete the top value on the stack (throw it away).
  100. .TP
  101. .B D
  102. empty the stack completely (throw all stacked data away).
  103. .TP
  104. .B +
  105. add top two items on the stack, place sum on the stack.
  106. .TP
  107. .B \-
  108. subtract top of stack from next to top, place difference on the stack.
  109. .TP
  110. .BR * " or " x " or " X
  111. multiply top two items on the stack, place product on the stack.
  112. Since
  113. .QU "*"
  114. is usually expanded by the shell,
  115. .I hp
  116. allows
  117. .QU x
  118. or
  119. .QU X
  120. as synonyms for
  121. .QU * .
  122. (The idea is that
  123. .QU x
  124. is hopefully reminiscent of the grade-school notation used for multiplication.)
  125. .TP
  126. .B /
  127. divide next to top of stack by top of stack, place quotient on the stack.
  128. .TP
  129. .B %
  130. divide next to top of stack by top of stack, place remainder on the stack.
  131. .TP
  132. .BR ^ " or " :
  133. evaluate (next to top of stack) to the (top of stack) power, place
  134. result on the stack.
  135. The
  136. .QU : ,
  137. while not very mnemonic, is not special to the Bourne shell
  138. .RI ( sh (1)),
  139. and so can be used
  140. on the command line.
  141. .TP
  142. .B <
  143. if next to top of stack is less than top of stack, place a 1 on the
  144. stack; otherwise, place a 0 on the stack.
  145. .TP
  146. .B =
  147. if next to top of stack equals top of stack, place a 1 on the stack;
  148. otherwise, place a 0 on the stack.
  149. .TP
  150. .B >
  151. if next to top of stack is greater than top of stack, place a 1 on the
  152. stack; otherwise, place a 0 on the stack.
  153. .TP
  154. .B &
  155. if next to top of stack is nonzero and top of stack is nonzero, place
  156. a 1 on the stack; otherwise, place a 0 on the stack.
  157. .TP
  158. .B |
  159. if next to top of stack is nonzero or top of stack is nonzero,
  160. place a 1 on the stack; otherwise, place a 0 on the stack.
  161. .TP
  162. .B !
  163. if top of stack is nonzero, replace it with a 0; if it is zero,
  164. replace it with a 1 (logical negation).
  165. .TP
  166. .BR q " or " Q
  167. exit.
  168. .I Hp
  169. will also exit when it sees an end-of-file (usually control-D).
  170. .SH EXAMPLES
  171. .nf
  172. hp 32.75 4.5 '*'
  173. hp
  174. 1 2 3 4 5 6 7P++++++pd
  175. 3.1416 2.7183^ 2.7183 3.1416^>p
  176. .fi
  177. .SH SEE ALSO
  178. .IR eval (1),
  179. .IR lex (1),
  180. .IR yacc (1)
  181. .SH DIAGNOSTICS
  182. .TP
  183. stack overflow
  184. if an attempt is made to push too many items on the stack.
  185. The stack size is currently limited to about 100.
  186. .TP
  187. stack underflow
  188. if an attempt is made to perform an operation
  189. with insufficient operands on the stack.
  190. .TP
  191. <char>: unrecognized command
  192. if a character not corresponding to
  193. any command appears in an expression.
  194. SHAR_EOF
  195. fi
  196. echo shar: "extracting 'Makefile'" '(558 characters)'
  197. if test -f 'Makefile'
  198. then
  199.     echo shar: "will not over-write existing file 'Makefile'"
  200. else
  201. cat << \SHAR_EOF > 'Makefile'
  202. # makefile for 'hp' --- reverse polish notation calculator
  203.  
  204. CFLAGS= -O
  205. YFLAGS= -d
  206. DESTDIR=/usr/local/bin
  207. MANSEC=l
  208. CP= cp
  209.  
  210. OBJS = hp.o hp.gram.o hp.scan.o
  211.  
  212. hp: $(OBJS)
  213.     $(CC) $(CFLAGS) $(OBJS) -lm -ll -o hp
  214.  
  215. hp.scan.o : y.tab.h
  216.     lex hp.scan.l
  217.     cc -O -c lex.yy.c
  218.     rm lex.yy.c
  219.     mv lex.yy.o hp.scan.o
  220.  
  221. hp.gram.o y.tab.h : hp.gram.y
  222.  
  223. install: hp hp.1
  224.     $(CP) hp $(DESTDIR)
  225.     $(CP) hp.1 /usr/man/man$(MANSEC)/hp.$(MANSEC)
  226.  
  227. print:
  228.     pr hp.gram.y hp.scan.l hp.h hp.c | lpr
  229.     nroff -man hp.1 | col | lpr
  230.  
  231. clean:
  232.     rm -f $(OBJS) hp.gram.c y.tab.h
  233.  
  234. clobber: clean
  235.     rm -f hp
  236. SHAR_EOF
  237. fi
  238. echo shar: "extracting 'hp.gram.y'" '(2209 characters)'
  239. if test -f 'hp.gram.y'
  240. then
  241.     echo shar: "will not over-write existing file 'hp.gram.y'"
  242. else
  243. cat << \SHAR_EOF > 'hp.gram.y'
  244. /* yacc grammar for hp reverse polish calculator */
  245.  
  246. %{
  247. #include "y.tab.h"
  248.  
  249. #include "hp.h"
  250.  
  251. int i;
  252. extern int sound();
  253. extern double ctod(), pow(), fmod();
  254. %}
  255.  
  256. %start expression
  257. %term DOT DIGIT BIGP LITTLEP PLUS MINUS STAR SLASH PERCENT POW
  258. %term AND OR NOT EQ LT GT LE GE BIGD LITTLED QUIT
  259.  
  260. %%
  261. expression : constant_or_command_list
  262.     |
  263.     ;
  264.  
  265. constant_or_command_list : constant_or_command_list constant_or_command
  266.     | constant_or_command
  267.     ;
  268.  
  269. constant_or_command : constant
  270.     | command
  271.     ;
  272.  
  273. constant : DOT    { push(ctod(line, & scanptr)); scanptr--; }
  274.     | DIGIT    { push(ctod(line, & scanptr)); scanptr--; }
  275.     ;
  276.  
  277. command : LITTLEP    { if (sound(1)) printf("%lf\n", stack[sp]); }
  278.  
  279.     | BIGP    {
  280.             for (i = 1; i < sp; i++)
  281.                 printf("%lf\n", stack[i]);
  282.         }
  283.  
  284.     | PLUS    {
  285.             if (sound(2)) {
  286.                 stack[sp - 1] += stack[sp];
  287.                 sp--;
  288.             }
  289.         }
  290.  
  291.     | MINUS    {
  292.             if (sound(2)) {
  293.                 stack[sp - 1] -= stack[sp];
  294.                 sp--;
  295.             }
  296.         }
  297.  
  298.     | STAR    {
  299.             if (sound(2)) {
  300.                 stack[sp - 1] *= stack[sp];
  301.                 sp--;
  302.             }
  303.         }
  304.  
  305.     | SLASH    {
  306.             if (sound(2)) {
  307.                 stack[sp - 1] /= stack[sp];
  308.                 sp--;
  309.             }
  310.         }
  311.  
  312.     | PERCENT    {
  313.                 if (sound(2)) {
  314.                     stack[sp - 1] = fmod(stack[sp - 1], stack[sp]);
  315.                     sp--;
  316.                 }
  317.             }
  318.  
  319.     | POW    {
  320.             if (sound(2)) {
  321.                 stack[sp - 1] = pow(stack[sp - 1], stack[sp]);
  322.                 sp--;
  323.             }
  324.         }
  325.  
  326.     | LITTLED    { if (sound(1)) sp--; }
  327.  
  328.     | BIGD        { sp = 0; }
  329.  
  330.     | LT    {
  331.             if (sound(2)) {
  332.                 if (stack[sp - 1] < stack[sp])
  333.                     stack[sp - 1] = 1.0;
  334.                 else
  335.                     stack[sp - 1] = 0.0;
  336.                 sp--;
  337.             }
  338.         }
  339.  
  340.     | EQ    {
  341.             if (sound(2)) {
  342.                 if (stack[sp - 1] == stack[sp])
  343.                     stack[sp - 1] = 1.0;
  344.                 else
  345.                     stack[sp - 1] = 0;
  346.                 sp--;
  347.             }
  348.         }
  349.  
  350.     | GT    {
  351.             if (sound(2)) {
  352.                 if (stack[sp - 1] > stack[sp])
  353.                     stack[sp - 1] = 1.0;
  354.                 else
  355.                     stack[sp - 1] = 0.0;
  356.                 sp--;
  357.             }
  358.         }
  359.  
  360.     | AND    {
  361.             if (sound(2)) {
  362.                 if (stack[sp - 1] != 0.0 && stack[sp] != 0.0)
  363.                     stack[sp - 1] = 1.0;
  364.                 else
  365.                     stack[sp - 1] = 0.0;
  366.                 sp--;
  367.             }
  368.         }
  369.  
  370.     | OR    {
  371.             if (sound(2)) {
  372.                 if (stack[sp - 1] != 0.0 || stack[sp] != 0.0)
  373.                     stack[sp - 1] = 1.0;
  374.                 else
  375.                     stack[sp - 1] = 0.0;
  376.                 sp--;
  377.             }
  378.         }
  379.  
  380.     | NOT    {
  381.             if (sound(1)) if (stack[sp] != 0.0)
  382.                     stack[sp] = 0.0;
  383.                 else
  384.                     stack[sp] = 1.0;
  385.         }
  386.  
  387.     | QUIT    { exit (0); }
  388.     ;
  389. SHAR_EOF
  390. fi
  391. echo shar: "extracting 'hp.scan.l'" '(572 characters)'
  392. if test -f 'hp.scan.l'
  393. then
  394.     echo shar: "will not over-write existing file 'hp.scan.l'"
  395. else
  396. cat << \SHAR_EOF > 'hp.scan.l'
  397. %{
  398. /* hp.scan.l --- lex scanner for hp calculator */
  399.  
  400. #include "y.tab.h"
  401. #undef input
  402. #undef unput
  403. %}
  404.  
  405. %%
  406. "."    return (DOT);
  407. [0-9]    return (DIGIT);
  408. "P"    return (BIGP);
  409. "p"    return (LITTLEP);
  410. "+"    return (PLUS);
  411. "-"    return (MINUS);
  412. [Xx*]    return (STAR);
  413. "/"    return (SLASH);
  414. "%"    return (PERCENT);
  415. [:^]    return (POW);
  416. "&"    return (AND);
  417. "|"    return (OR);
  418. "!"    return (NOT);
  419. "="    return (EQ);
  420. "<"    return (LT);
  421. ">"    return (GT);
  422. "<="    return (LE);
  423. ">="    return (GE);
  424. "D"    return (BIGD);
  425. "d"    return (LITTLED);
  426. [Qq]    return (QUIT);
  427. [ \t\n]    ;
  428. .    fprintf(stderr, "%s: unknown command.\n", yytext);
  429. SHAR_EOF
  430. fi
  431. echo shar: "extracting 'hp.h'" '(123 characters)'
  432. if test -f 'hp.h'
  433. then
  434.     echo shar: "will not over-write existing file 'hp.h'"
  435. else
  436. cat << \SHAR_EOF > 'hp.h'
  437. /* hp.h --- external declarations for hp */
  438.  
  439. extern double stack[];
  440. extern int scanptr;
  441. extern int sp;
  442. extern char line[];
  443. SHAR_EOF
  444. fi
  445. echo shar: "extracting 'hp.c'" '(2416 characters)'
  446. if test -f 'hp.c'
  447. then
  448.     echo shar: "will not over-write existing file 'hp.c'"
  449. else
  450. cat << \SHAR_EOF > 'hp.c'
  451. /* hp --- reverse Polish notation calculator program */
  452.  
  453. #include <stdio.h>
  454. #include <ctype.h>
  455.  
  456. #define MAXSTACK    100
  457. #define TRUE        1
  458. #define FALSE        0
  459.  
  460. double stack[MAXSTACK + 1];
  461. int scanptr = -1;
  462. int sp = 0;
  463. char line[BUFSIZ*4];
  464.  
  465. extern char *strcpy();
  466.  
  467. main(argc, argv)
  468. int argc;
  469. char **argv;
  470. {
  471.     int i, l;
  472.     int sound();
  473.  
  474.     if (argc > 1) {
  475.         l = 0;
  476.         /* concatenate args into one line for input() to use... */
  477.         for (i = 1; argv[i] != NULL; i++) {
  478.             (void) strcpy(& line[l], argv[i]);
  479.             l += strlen(argv[i]);
  480.             line[l] = ' ';
  481.             l++;
  482.         }
  483.         line[l] = '\0';
  484.         scanptr = -1;
  485.         yyparse();
  486.         if (sound(1))
  487.             printf("%1.3lf\n", stack[sp]);
  488.     } else
  489.         while (fgets(line, sizeof line, stdin) != NULL) {
  490.             scanptr = -1;
  491.             yyparse();
  492.         }
  493.     
  494.     exit(0);
  495. }
  496.  
  497. /* ctod --- do atof, but increment pointer into the line buffer */
  498.  
  499. double ctod(text, indx)
  500. char text[];
  501. int *indx;
  502. {
  503.     double result, atof();
  504.     char buf[BUFSIZ];
  505.     int i = 0;
  506.  
  507.     while (isdigit(text[*indx])) {
  508.         buf[i++] = text[*indx];
  509.         (*indx)++;
  510.     }
  511.  
  512.     if (text[*indx] == '.') {
  513.         buf[i++] = '.';
  514.         (*indx)++;
  515.     }
  516.     
  517.     while (isdigit(text[*indx])) {
  518.         buf[i++] = text[*indx];
  519.         (*indx)++;
  520.     }
  521.  
  522.     if (text[*indx] == 'e' ||  text[*indx] == 'E') {
  523.         buf[i++] = text[*indx];
  524.         (*indx)++;
  525.     
  526.         if (text[*indx] == '-' || text[*indx] == '+') {
  527.             buf[i++] = text[*indx];
  528.             (*indx)++;
  529.         }
  530.  
  531.         while (isdigit(text[*indx])) {
  532.             buf[i++] = text[*indx];
  533.             (*indx)++;
  534.         }
  535.     }
  536.  
  537.     buf[i] = '\0';
  538.  
  539.     result = atof(buf);
  540.     return result;
  541. }
  542.  
  543. /* fmod --- do floating modulus */
  544.  
  545. double fmod(x, y)
  546. double x, y;
  547. {
  548.     extern double modf();
  549.     extern double fabs();
  550.     double f;
  551.     int flag = 0;
  552.     double ipart;
  553.  
  554.     if (y == 0.0)
  555.         return x;
  556.  
  557.     flag = (x < 0.0);
  558.     x = fabs(x);
  559.     y = fabs(y);
  560.     (void) modf(x / y, & ipart);
  561.     f = x - y * ipart;
  562.     return (flag ? -f : f);
  563. }
  564.  
  565. /* push --- push one item onto the stack */
  566.  
  567. push(stuff)
  568. double stuff;
  569. {
  570.     if (sp > MAXSTACK)
  571.         fprintf(stderr, "stack overflow\n");
  572.     else {
  573.         sp++;
  574.         stack[sp] = stuff;
  575.     }
  576. }
  577.  
  578.  
  579.  
  580. /* sound --- sound out the depth of the stack */
  581.  
  582. int sound(depth)
  583. int depth;
  584. {
  585.     if (sp < depth) {
  586.         fprintf(stderr, "stack underflow\n");
  587.         return FALSE;
  588.     } else
  589.         return TRUE;
  590. }
  591.  
  592. int input()
  593. {
  594.     register int c;
  595.  
  596. again:
  597.     scanptr++;
  598.     if ((c = line[scanptr]) == '\0') {
  599.         scanptr = -1;
  600.         return 0;
  601.     } else if (isspace(c))
  602.         goto again;
  603.     else {
  604.         return c;
  605.     }
  606. }
  607.  
  608. int unput(c)
  609. int c;
  610. {
  611.     line[--scanptr] = c;
  612. }
  613.  
  614. int yyerror(s)
  615. char *s;
  616. {
  617.     fprintf(stderr, "hp: %s\n", s);
  618. }
  619. SHAR_EOF
  620. fi
  621. exit 0
  622. #    End of shell archive
  623.  
  624. exit 0 # Just in case...
  625.